package oss

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"gitee.com/iece/common/log"
	"gitee.com/iece/common/utils"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

var rou *ossClient

type ossClient struct {
	cli  *oss.Client
	opts *RrsOssOptions
}

// 加载配置初始化oss
func OpenRrsOssClient() {
	opts := &RrsOssOptions{}
	err := opts.Load()
	if err != nil {
		log.Error(err)
		return
	}
	cli, err := oss.New(opts.Endpoint, opts.AppKey, opts.AppSecret)
	if err != nil {
		log.Error(err)
		return
	}

	rou = &ossClient{
		cli:  cli,
		opts: opts,
	}
}

// 从网络地址下载后上传
func (rou *ossClient) UploadURL(picURL, dirName string) (string, error) {
	res, err := http.Get(picURL)
	if err != nil {
		return "", err
	}
	if res.StatusCode >= 299 {
		err = errors.New(picURL + " status code: " + strconv.Itoa(res.StatusCode))
		log.Error(err)
		return "", err
	}
	defer res.Body.Close()
	return rou.UploadReader(res.Body, dirName, parseName(picURL))
}

// 上传二进制
func (rou *ossClient) UploadBytes(bs []byte, dirName, fileName string) (string, error) {
	return rou.UploadReader(bytes.NewReader(bs), dirName, fileName)
}

// 上传流数据
func (rou *ossClient) UploadReader(reader io.Reader, dirName, fileName string) (string, error) {
	const bucketName = "rrs-files"
	if _, ok := dirMap[dirName]; !ok {
		return "", errors.New("bucket is empty")
	}

	cli := rou.cli

	bucket, err := cli.Bucket(bucketName)
	if err != nil {
		return "", err
	}
	now := time.Now()
	dirName += now.Format("20060102") // 月份目录
	sb := strings.Builder{}
	sb.WriteString(dirName)
	sb.WriteString("/")
	sb.WriteString(strconv.FormatInt(now.UnixMilli(), 10))
	sb.WriteString("-")
	sb.WriteString(fileName)
	ossName := sb.String()
	err = bucket.PutObject(ossName, reader)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("https://%s.%s/%s", bucketName, rou.opts.Endpoint, ossName), nil
}

func parseName(picURL string) string {
	uri, _ := url.Parse(picURL)

	pieces := strings.Split(uri.Path, "/")

	l := len(pieces)
	if l == 0 {
		return utils.GenIDStr()
	}

	return pieces[l-1]
}
